package com.chenbei.schedule.job;

import com.chenbei.common.util.DateUtil;
import com.chenbei.common.util.SpringBeanUtil;
import com.chenbei.schedule.domain.ScheduleJob;
import com.chenbei.schedule.domain.ScheduleJobLog;
import com.chenbei.schedule.service.ScheduleJobLogService;
import com.chenbei.schedule.service.ScheduleJobService;
import com.chenbei.schedule.util.MethodInvocationUtil;
import lombok.extern.slf4j.Slf4j;
import org.quartz.CronExpression;
import org.quartz.JobExecutionContext;
import org.springframework.lang.NonNull;
import org.springframework.scheduling.quartz.QuartzJobBean;
import org.springframework.util.StopWatch;

import java.text.ParseException;
import java.time.LocalDateTime;
import java.util.Date;

@Slf4j
public class AbstractScheduleJob extends QuartzJobBean {


    protected AbstractScheduleJob(){}

    @Override
    protected void executeInternal(@NonNull JobExecutionContext context) {
        long jobId = context.getMergedJobDataMap().getLong("jobId");
        ScheduleJobService scheduleJobService = SpringBeanUtil.getBean(ScheduleJobService.class);
        ScheduleJobLogService scheduleJobLogService = SpringBeanUtil.getBean(ScheduleJobLogService.class);
        if (scheduleJobService != null && scheduleJobLogService != null) {
            ScheduleJob scheduleJob = scheduleJobService.getById(jobId);
            if (scheduleJob != null) {
                StopWatch stopWatch = new StopWatch();
                stopWatch.start();
                String errMsg = "";
                boolean status = false;

                try {
                    scheduleJob.setLastExecuteTime(LocalDateTime.now());
                    doExecute(context, scheduleJob);
                    status = true;
                } catch (Exception e) {
                    errMsg = e.getMessage();
                }

                stopWatch.stop();
                long totalTimeMillis = stopWatch.getTotalTimeMillis();

                //更新并保存运行日志
                scheduleJob.setLatestExecuteStatus(status ? 1 : 0);
                try {
                    scheduleJob.setNextExecuteTime(computeNextExecuteTime(scheduleJob));
                    scheduleJobService.updateById(scheduleJob);

                    ScheduleJobLog scheduleJobLog = new ScheduleJobLog();
                    scheduleJobLog.setJobId(jobId);
                    scheduleJobLog.setStatus(status ? 1 : 0);
                    scheduleJobLog.setStartTime(scheduleJob.getLastExecuteTime());
                    scheduleJobLog.setExceptionMessage(errMsg);
                    scheduleJobLog.setTotalExecutionTime(totalTimeMillis);
                    scheduleJobLogService.save(scheduleJobLog);
                } catch (ParseException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }

    protected void doExecute(JobExecutionContext context, ScheduleJob scheduleJob) throws Exception {
        MethodInvocationUtil.MethodInvocation methodInvocation = MethodInvocationUtil.parseInvokeTarget(scheduleJob);
        if (methodInvocation != null) {
            try {
                Object o = MethodInvocationUtil.invokeMethod(methodInvocation, context, scheduleJob);
                log.info("执行结果: {}", o);
            } catch (Exception e) {
                throw new Exception(e.getMessage());
            }
        }
    }

    /**
     * 获取下一个执行时间
     * @param scheduleJob 任务模板
     * @return LocalDateTime
     */
    private LocalDateTime computeNextExecuteTime(ScheduleJob scheduleJob) throws ParseException {
        CronExpression cronExpression = new CronExpression(scheduleJob.getCronExpress());
        Date nextValidTimeAfter = cronExpression.getNextValidTimeAfter(new Date());
        return DateUtil.toLocalDateTime(nextValidTimeAfter);
    }
}
